/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/** ************************************************************************************************
 * \file     Firewall_Mac.c                                                                   *
 * \brief    Semidrive Firewall MAC Driver                                                              *
 *                                                                                                 *
 **************************************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif

/***************************************************************************************************
 *                                 Private Macro definition                                        *
 **************************************************************************************************/
#if (defined(CFG_PLATFORM_MCAL))
#include "RegHelper.h"
#endif /** #if (defined(CFG_PLATFORM_MCAL)) */

#include "Firewall_Mac_Ip.h"

/***************************************************************************************************
 *                                 Private Macro definition                                        *
 **************************************************************************************************/
/** \brief The offset address of the master domain assignment register. */
#define MAC_MDA_OFFSET_ADDR(n)    ((uint32_t)((uint32_t)(n)*0x8U))
/** \brief The bit mask of locking the master domain assignment register. */
#define MAC_MDA_LOCK              ((uint32_t)(0x1UL << 31U))
/** \brief The domain id range is 0 ~ 15. */
#define MAC_MDA_DID_VALUE(did)    ((uint32_t)(did)&0xfU)

/** \brief The offset address of the master transaction attribute register. */
#define MAC_MAA_OFFSET_ADDR(n)           ((uint32_t)(0x4U + ((uint32_t)(n)*0x8U)))
/** \brief The bit mask of locking the master transaction privileged/user attribute. */
#define MAC_MAA_PRI_LOCK          ((uint32_t)(0x1UL << 5U))
/** \brief The bit mask of locking the master transaction secure/non-secure attribute. */
#define MAC_MAA_SEC_LOCK          ((uint32_t)(0x1UL << 2U))

/** \brief The offset address of the global manager register. */
#define MAC_ACS_DID               ((uint32_t)0x200U)
/** \brief The bit mask of locking the global manager configuration. */
#define MAC_ACS_DID_LOCK          ((uint32_t)(0x1UL << 31U))
/** \brief The domain id range is 0 ~ 7. */
#define MAC_ACS_DID_VALUE(did)    ((uint32_t)((did)&0xfU))

/** \brief The offset address of the masters attributes update. */
#define MAC_MAS_CFG_UP            ((uint32_t)0x204U)
/** \brief The bit mask of masters config flag. */
#define MAC_MAS_CFG_UP_CLEAR      ((uint32_t)(0x1UL))

/** \brief The offset address of the response error disable register. */
#define MAC_RESP_ERR_DIS          ((uint32_t)0x3FCU)
/** \brief The bit mask of locking the response error disable configurations for MAC/MPC/PPC. */
#define MAC_RESP_ERR_DIS_ALL_LOCK ((uint32_t)(0x1UL << 31U))
/** \brief The bit mask of locking the response error disable configurations for MAC. */
#define MAC_RESP_ERR_DIS_MAC_LOCK ((uint32_t)(0x1UL << 30U))
/** \brief The bit mask of disabling the response error feature for MAC/MPC/PPC. */
#define MAC_RESP_ERR_DIS_ALL_DIS  ((uint32_t)(0x1UL << 1U))
/** \brief The bit mask of disabling the response error feature for MAC. */
#define MAC_RESP_ERR_DIS_MAC_DIS  ((uint32_t)(0x1UL))

/** \brief The offset address of the MAC interrupt status register. */
#define MAC_FUNC_INT_STA          ((uint32_t)0x2E0U)
/** \brief The offset address of the MAC interrupt controller register. */
#define MAC_FUNC_INT_STA_EN       ((uint32_t)0x2E4U)
/** \brief The offset address of the MAC interrupt signal register. */
#define MAC_FUNC_INT_SIG_EN       ((uint32_t)0x2E8U)

#if (defined(CFG_PLATFORM_MCAL))
#define FIREWALL_START_SEC_CODE
#include "Firewall_MemMap.h"
#endif /** #if (defined(CFG_PLATFORM_MCAL)) */

/***************************************************************************************************
 *                                  Global Function Declarations                                   *
 **************************************************************************************************/
/**
 * \brief Configure the mapping between masters and domains in MAC module.
 *
 * This function configure the mapping between masters and domains in MAC module.
 * The System should call Firewall_MacLockDomainAssignment() to lock the MAC
 * configurations after calling this function.
 *
 * \param[in] macBaseAddr the address of the MAC module.
 * \param[in] macConfigPtr the configuration of the MAC.
 *
 * \return The result of the MAC initialization function
 * \details - return FIREWALL_E_OK : initializa MAC success.
 *          - return FIREWALL_E_NULL_POINTER : The pointer is a NULL_PTR.
 */
lld_status_t Firewall_MacConfigure(const Firewall_ControllerType *ctrl,
                                     const Firewall_MacConfigType *macConfigPtr)
{
    lld_status_t ret_val = (lld_status_t)FIREWALL_E_OK;
    uint32_t macBaseAddr;
    uint8_t master_num;
    uint8_t domain_num;

    /* #10 Check the parameters. */
    if (NULL == macConfigPtr)
    {
        ret_val = (lld_status_t)FIREWALL_E_NULL_POINTER;
    }
    else
    {
        macBaseAddr = ctrl->macBaseAddr;
        /* #20 Configure the firewall permission for main core. */
        if (MAC_MDA_LOCK != (MAC_MDA_LOCK & readl(macBaseAddr +
                            MAC_MDA_OFFSET_ADDR(FIREWALL_MASTER_ID_MAIN))))
        {
            /* Assign the main master to the manager domain, and lock this configuration.
            */
            writel(MAC_MDA_DID_VALUE(FIREWALL_DOMAIN_ID_MANAGER),
                macBaseAddr + MAC_MDA_OFFSET_ADDR(FIREWALL_MASTER_ID_MAIN));
            writel(MAC_MDA_DID_VALUE(FIREWALL_DOMAIN_ID_MANAGER) | MAC_MDA_LOCK,
                macBaseAddr + MAC_MDA_OFFSET_ADDR(FIREWALL_MASTER_ID_MAIN));
        }
        if (MAC_ACS_DID_LOCK != (MAC_ACS_DID_LOCK & readl(macBaseAddr + MAC_ACS_DID)))
        {
            /* Set the global manager. */
            writel(MAC_MDA_DID_VALUE(FIREWALL_DOMAIN_ID_MANAGER),
                macBaseAddr + MAC_ACS_DID);
            writel(MAC_MDA_DID_VALUE(FIREWALL_DOMAIN_ID_MANAGER) | MAC_ACS_DID_LOCK,
                macBaseAddr + MAC_ACS_DID);
        }

        /* #30 Assign all masters to the different domain. */
        for (domain_num = 0U; domain_num < FIREWALL_DOMAIN_MAXNUM; domain_num++)
        {
            if (NULL != macConfigPtr[domain_num])
            {
                for (master_num = 0U;
                     macConfigPtr[domain_num][master_num] < FIREWALL_MASTER_MAXNUM; ++master_num)
                {
                    if (MAC_MDA_LOCK == (MAC_MDA_LOCK & readl(macBaseAddr +
                                            MAC_MDA_OFFSET_ADDR(macConfigPtr[domain_num][master_num]))))
                    {
                        continue;
                    }
                    /* Assign the master to the specified domain. */
                    writel(MAC_MDA_DID_VALUE(domain_num),
                           macBaseAddr + MAC_MDA_OFFSET_ADDR(macConfigPtr[domain_num][master_num]));
                    /* Lock the master transaction attribute. */
                    writel(MAC_MAA_PRI_LOCK | MAC_MAA_SEC_LOCK,
                           macBaseAddr + MAC_MAA_OFFSET_ADDR(macConfigPtr[domain_num][master_num]));

                    /* Update the masters attributes flag (self-clear). */
                    writel(MAC_MAS_CFG_UP_CLEAR, macBaseAddr + MAC_MAS_CFG_UP);
                }
            }
        }

        if (0U == ctrl->resErrEnable)
        {
            /* #50 Disable respone error when illegal access */
            writel(MAC_RESP_ERR_DIS_ALL_DIS | MAC_RESP_ERR_DIS_MAC_DIS,
                macBaseAddr + MAC_RESP_ERR_DIS);
            writel(MAC_RESP_ERR_DIS_ALL_LOCK | MAC_RESP_ERR_DIS_MAC_LOCK,
                macBaseAddr + MAC_RESP_ERR_DIS);
        }
    }

    return ret_val;
}

/**
 * \brief Assigns the specified master to a domain.
 *
 * This function is called by Firewall_AssignDomain().
 *
 * \param[in] macBaseAddr the address of the MAC module.
 * \param[in] master_id the id of the master.
 * \param[in] domain_id the id of the domain.
 *
 * \return    The result of this function.
 * \details - return FIREWALL_E_OK :  Change domain success.
 *          - return FIREWALL_E_MAC_MASTER_ID : invalid master id.
 *          - return FIREWALL_E_MAC_DOMAIN_ID : invalid domain id.
 *          - return FIREWALL_E_MAC_LOCKED : domain assign has been locked.
 */
lld_status_t Firewall_MacAssignDomain(uint32_t macBaseAddr, uint8_t master_id,
                                         uint8_t domain_id)
{
    lld_status_t ret_val = (lld_status_t)FIREWALL_E_OK;

    /* #10 Check the parameters. */
    if (master_id >= FIREWALL_MASTER_MAXNUM)
    {
        ret_val = (lld_status_t)FIREWALL_E_MAC_MASTER_ID;
    }
    else if (domain_id >= FIREWALL_DOMAIN_MAXNUM)
    {
        ret_val = (lld_status_t)FIREWALL_E_MAC_DOMAIN_ID;
    }
    else if (0U !=
             (MAC_MDA_LOCK & readl(macBaseAddr + MAC_MDA_OFFSET_ADDR(master_id))))
    {
        ret_val = (lld_status_t)FIREWALL_E_MAC_LOCKED;
    }
    else
    {
        /* #20 Assign the master to the specified domain. */
        writel(MAC_MDA_DID_VALUE(domain_id),
               macBaseAddr + MAC_MDA_OFFSET_ADDR(master_id));
    }

    return ret_val;
}

/**
 * \brief Lock the configuration of the map between masters and domains
 *        in MAC module.
 *
 * This function lock the configuration of map between masters and domains
 * in MAC module.
 * This function is called by Firewall_LockDomainAssignment().
 *
 * \param[in] macBaseAddr the address of the MAC module.
 */
void Firewall_MacLockDomainAssignment(uint32_t macBaseAddr)
{
    uint8_t master_num;

    for (master_num = 0U; master_num < FIREWALL_MASTER_MAXNUM; ++master_num)
    {
        writel(MAC_MDA_LOCK | readl(macBaseAddr + MAC_MDA_OFFSET_ADDR(master_num)),
               macBaseAddr + MAC_MDA_OFFSET_ADDR(master_num));
    }

    /* Update the masters attributes flag(self-clear). */
    writel(MAC_MAS_CFG_UP_CLEAR, macBaseAddr + MAC_MAS_CFG_UP);
}

/**
 * \brief Clear the interrupt status of the MAC module.
 *
 * \param[in] macBaseAddr the address of the MAC module.
 */
void Firewall_MacClearInterrupt(uint32_t macBaseAddr)
{
    /* #10 Clear the interrupt of the MAC module. */
    /* Disable the interrupt of the mac. */
    writel(FIREWALL_REG_VALUE_MIN, macBaseAddr + MAC_FUNC_INT_STA_EN);
    /* Disable the interrupt signal of the mac. */
    writel(FIREWALL_REG_VALUE_MIN, macBaseAddr + MAC_FUNC_INT_SIG_EN);
    /* Clear the interrupt status of the mac. */
    writel(FIREWALL_REG_VALUE_MAX, macBaseAddr + MAC_FUNC_INT_STA);
}

#if (defined(CFG_PLATFORM_MCAL))
#define FIREWALL_STOP_SEC_CODE
#include "Firewall_MemMap.h"
#endif /** #if (defined(CFG_PLATFORM_MCAL)) */

#ifdef __cplusplus
}
#endif

/* End of file */
